/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Javabeans;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

/**
 *
 * @author Tariq
 */
public class DataPoint implements Comparable, Cloneable{
    private static DataPoint testPoint;
    private Double distanceFromTestPoint=-1.0;

    private static  ArrayList<String> attributeNames;
    private static ArrayList<Double> attributeWeights = new ArrayList<Double>();
    private static HashMap<Integer, Double[]> attributeStats = new HashMap<Integer, Double[]>();
    private ArrayList<Double> attributeValues;
    
    private static int outputIndex;
    private static String outputName;
    private String outputValue;

    public DataPoint(String[] values){
        attributeValues = new ArrayList<Double>();
        attributeWeights= new ArrayList<Double>();
        addAttributes(values);
    }
    public double getDistanceFromTestPoint(){
        return distanceFromTestPoint;
    }
    public static void setTestPoint(DataPoint n){
        testPoint = n;
    }
    public static DataPoint getTestPoint(){
        return testPoint;
    }
    public static String[]  getAttributeNames(){
        return DataPoint.attributeNames.toArray(new String[0]);
    }
    public static void  setAttributeNames(String[] names, int outputIndex){
        attributeNames = new ArrayList<String>();
        DataPoint.outputIndex = outputIndex;
        for(int i = 0; i<names.length;i++){
            if(i!=outputIndex){
                attributeNames.add(names[i]);
            }else{
                outputName=names[i];
            }
        }
    }
    public Double[] getAttributeValues(){
        return this.attributeValues.toArray(new Double[0]);
    }

    public void addAttributes (String[] values){
        for(int i = 0; i<values.length;i++){
            if(i!=outputIndex){
                attributeValues.add(Double.valueOf(values[i]));
            }else{
                this.outputValue=values[i];
            }
        }
    }

    public void setAttribute(int index, double value){
        attributeValues.set(index, value);
    }
    public static HashMap<Integer, Double[]> getAttributeStats(){
        return DataPoint.attributeStats;
    }
    public static Double[] getAttributeStats(int index){
        return DataPoint.attributeStats.get(index);
    }
    public static void setAttributeStats(int index, Double[] values){
        attributeStats.put(index,values);
    }


    public static DataPoint convertToDataPoint (String[] values){
        DataPoint customer = new DataPoint(values);
        return customer;
    }
    public void calculateDistanceFromTestPoint(){
        distanceFromTestPoint=distance(testPoint);
    }
    public String getOutputValue(){
        return this.outputValue;
    }
    public void setOutputValue(String outputValue){
        this.outputValue = outputValue;
    }
    public Double  distance (DataPoint oldCustomer){
        ArrayList<Double> a = oldCustomer.attributeValues;
        ArrayList<Double> b = this.attributeValues;

        ArrayList<Double> w = this.attributeWeights;

        int count=0;
        if(a.size()==b.size()){
            count = a.size();
        }else{
            return null;
        }

        double distance=0.0;
        for(int i=0;i<count;i++){
            distance+=Math.pow(
                (w.get(i)*normalizeAttribute(i,a.get(i)))-(w.get(i)*normalizeAttribute(i,b.get(i)))
                ,2);
            //System.out.print("("+normalizeAttribute(i,a.get(i))+"-"+normalizeAttribute(i,b.get(i))+")=");
            //System.out.print(normalizeAttribute(i,a.get(i))-normalizeAttribute(i,b.get(i))+"\n");
        }
        //System.out.println("distance: "+distance);
        distance = Math.sqrt(distance);
        return distance;
    }
    public String toString(){
        String row="";
        Iterator it = attributeValues.iterator();
        while(it.hasNext()){
            row += (Double)it.next()+", ";
        }
        row +=outputValue;
        return row;
    }
    public int compareTo(Object o) {
        DataPoint otherCustomer = (DataPoint)o;
        return this.distanceFromTestPoint.compareTo(otherCustomer.getDistanceFromTestPoint());
    }
    private double normalizeAttribute(int attIndex,double value){
        Double[] stats = DataPoint.attributeStats.get(attIndex);
        double max = stats[0];
        double min = stats[1];
        return (value-min)/(max-min);
    }
    public boolean isSameOutput(DataPoint other){
        return this.outputValue==other.outputValue;
    }
    public Object clone(){
    try{
      DataPoint cloned = (DataPoint)super.clone();
      return cloned;
    }
    catch(CloneNotSupportedException e){
      System.out.println(e);
      return null;
    }
    }
    public static void setAttributesWeight(ArrayList<Double> attributeWeights){
        if(attributeWeights.size()==attributeWeights.size()){
            DataPoint.attributeWeights = attributeWeights;
        }
    }
    public static void setAttributeWeight(int index, double weight){
        attributeWeights.set(index, weight);
    }
    public static ArrayList<Double> getAttributeWeights(){
        return attributeWeights;
    }
}
